return rc;
}
+static void evtchn_bind_to_user(struct per_user_data *u, int port)
+{
+ spin_lock_irq(&port_user_lock);
+ BUG_ON(port_user[port] != NULL);
+ port_user[port] = u;
+ unmask_evtchn(port);
+ spin_unlock_irq(&port_user_lock);
+}
+
static int evtchn_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
struct per_user_data *u = file->private_data;
evtchn_op_t op = { 0 };
- spin_lock_irq(&port_user_lock);
-
switch (cmd) {
case IOCTL_EVTCHN_BIND_VIRQ: {
struct ioctl_evtchn_bind_virq bind;
break;
rc = op.u.bind_virq.port;
- port_user[rc] = u;
- unmask_evtchn(rc);
+ evtchn_bind_to_user(u, rc);
break;
}
break;
rc = op.u.bind_interdomain.local_port;
- port_user[rc] = u;
- unmask_evtchn(rc);
+ evtchn_bind_to_user(u, rc);
break;
}
break;
rc = op.u.alloc_unbound.port;
- port_user[rc] = u;
- unmask_evtchn(rc);
+ evtchn_bind_to_user(u, rc);
break;
}
if (copy_from_user(&unbind, (void *)arg, sizeof(unbind)))
break;
- if (unbind.port >= NR_EVENT_CHANNELS) {
- rc = -EINVAL;
- } else if (port_user[unbind.port] != u) {
- rc = -ENOTCONN;
- } else {
- port_user[unbind.port] = NULL;
- mask_evtchn(unbind.port);
-
- op.cmd = EVTCHNOP_close;
- op.u.close.port = unbind.port;
- BUG_ON(HYPERVISOR_event_channel_op(&op));
+ rc = -EINVAL;
+ if (unbind.port >= NR_EVENT_CHANNELS)
+ break;
- rc = 0;
+ spin_lock_irq(&port_user_lock);
+
+ rc = -ENOTCONN;
+ if (port_user[unbind.port] != u) {
+ spin_unlock_irq(&port_user_lock);
+ break;
}
+
+ port_user[unbind.port] = NULL;
+ mask_evtchn(unbind.port);
+
+ spin_unlock_irq(&port_user_lock);
+
+ op.cmd = EVTCHNOP_close;
+ op.u.close.port = unbind.port;
+ BUG_ON(HYPERVISOR_event_channel_op(&op));
+
+ rc = 0;
break;
}
case IOCTL_EVTCHN_RESET: {
/* Initialise the ring to empty. Clear errors. */
+ spin_lock_irq(&port_user_lock);
u->ring_cons = u->ring_prod = u->ring_overflow = 0;
+ spin_unlock_irq(&port_user_lock);
rc = 0;
break;
}
break;
}
- spin_unlock_irq(&port_user_lock);
-
return rc;
}